package cn.studyjams.s1.contest.autohello;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;

import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.MutableData;
import com.google.firebase.database.Transaction;
import com.google.firebase.database.ValueEventListener;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import cn.studyjams.s1.contest.autohello.adapter.EventAdapter;
import cn.studyjams.s1.contest.autohello.model.Contact;
import cn.studyjams.s1.contest.autohello.model.Event;
import cn.studyjams.s1.contest.autohello.model.RepeatMode;
import cn.studyjams.s1.contest.autohello.receiver.NotificationReceiver;

public class HelloActivity extends BaseActivity implements View.OnClickListener {

    private final static String TAG = "HelloActivity";
    private final static int ADD_EVENT_REQUEST_CODE = 1;

    List<Event> mDataset;

    private int mEventType;
    List<Drawable> drawables;
    String[] titles;
    String[] descs;
    int[] colors;

    private DatabaseReference mDatabase;
    private FirebaseUser mUser;

    private RecyclerView mRecycler;
    private RecyclerView.Adapter mAdapter;

    private TextView empty;

    private String dateTime;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hello);
        Log.d(TAG, "onCreate");

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            // Show the Up button in the action bar.
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        mEventType = getIntent().getIntExtra("eventType", 0);

        /**
         * 全局变量初始化
         */
        mUser = FirebaseAuth.getInstance().getCurrentUser();
        mDatabase = FirebaseDatabase.getInstance().getReference();
        empty = (TextView) findViewById(R.id.empty_event);
        mRecycler = (RecyclerView) findViewById(R.id.events_holder);
        mDataset = new ArrayList<>();

        findViewById(R.id.fab).setOnClickListener(this);

        /**
         * ------------------------------------------------------
         */

        drawables = new ArrayList<>();
        drawables.add(ContextCompat.getDrawable(this, R.drawable.ic_hello));
        drawables.add(ContextCompat.getDrawable(this, R.drawable.ic_sunny));
        drawables.add(ContextCompat.getDrawable(this, R.drawable.ic_birthday));
        drawables.add(ContextCompat.getDrawable(this, R.drawable.ic_holiday));


        titles = new String[]{
                getResources().getString(R.string.custom_hello),
                getResources().getString(R.string.weather_cast),
                getResources().getString(R.string.happy_birthday),
                getResources().getString(R.string.festival_blessing)
        };

        descs = new String[]{
                getResources().getString(R.string.custom_hello_desc),
                getResources().getString(R.string.weather_cast_desc),
                getResources().getString(R.string.happy_birthday_desc),
                getResources().getString(R.string.festival_blessing_desc)
        };

        colors = new int[]{
                ContextCompat.getColor(this, R.color.tomato),
                ContextCompat.getColor(this, R.color.banana),
                ContextCompat.getColor(this, R.color.cucumber),
                ContextCompat.getColor(this, R.color.blueBerry),
                ContextCompat.getColor(this, R.color.grape),
                ContextCompat.getColor(this, R.color.defaultColor)
        };

        /**
         * #START# CollapsingToolbarLayout
         */
        CollapsingToolbarLayout CollapsingToolbarLayout = (CollapsingToolbarLayout)
                findViewById(R.id.collapsing_toolbar);
        ImageView toolbarIV = (ImageView) findViewById(R.id.toolbar_img);
        CollapsingToolbarLayout.setTitle(titles[mEventType]);
        toolbarIV.setImageDrawable(drawables.get(mEventType));
        /**
         * #END# CollapsingToolbarLayout
         */


        /**
         * #START# RecyclerView
         */
        mRecycler.setHasFixedSize(true);

        // Set up Layout Manager, reverse layout
        final LinearLayoutManager mManager = new LinearLayoutManager(this);
        mManager.setReverseLayout(true);
        mManager.setStackFromEnd(true);
        mRecycler.setLayoutManager(mManager);
        /**
         * #END# RecyclerView
         */


        /**
         * #START# Database ValueEvent listener
         */
        ValueEventListener valueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                mDataset.clear();

                if (dataSnapshot != null) {
                    empty.setVisibility(View.GONE);
                    HashMap<String, Object> dataSnapshotValue = (HashMap<String, Object>) dataSnapshot.getValue();
                    if (dataSnapshotValue != null) {
                        Set<String> set = dataSnapshotValue.keySet();

                        for (String eventId : set) {

                            List<Contact> receivers = new ArrayList<>();
                            RepeatMode repeatMode;

                            HashMap<String, Object> eventMap = (HashMap<String, Object>) dataSnapshotValue.get(eventId);

                            int eventType = Integer.parseInt(eventMap.get("type").toString());

                            if (eventType != mEventType) {
                                continue;
                            }
                            boolean isActive = Boolean.parseBoolean(eventMap.get("isActive").toString());
                            boolean isDelete = Boolean.parseBoolean(eventMap.get("isDelete").toString());

                            String id = eventMap.get("id").toString();
                            String content = eventMap.get("content").toString();
                            String tag = eventMap.get("tag").toString();
                            dateTime = eventMap.get("dateTime").toString();
                            int color = Integer.parseInt(eventMap.get("color").toString());
                            long requestCode = Long.parseLong(eventMap.get("requestCode").toString());

                            ArrayList<Map<String, Object>> contacts = (ArrayList<Map<String, Object>>) eventMap.get("receivers");
                            for (int i = 0; i < contacts.size(); i++) {
                                HashMap<String, Object> contactMap = (HashMap<String, Object>) contacts.get(i);
                                String name = contactMap.get("name").toString();
                                String phoneNumber = contactMap.get("phoneNumber").toString();
                                String emailAddress = contactMap.get("emailAddress").toString();
                                int contactType = Integer.parseInt(contactMap.get("type").toString());

                                Contact contact = new Contact(name, phoneNumber, emailAddress, contactType);
                                receivers.add(contact);
                            }

                            HashMap<String, Object> repeatModeMap = (HashMap<String, Object>) eventMap.get("repeatMode");
                            int repeatType = Integer.parseInt(repeatModeMap.get("repeatType").toString());
                            int howOften = Integer.parseInt(repeatModeMap.get("howOften").toString());
                            int endCondition = Integer.parseInt(repeatModeMap.get("endCondition").toString());
                            String endDateTime = repeatModeMap.get("endDateTime").toString();
                            int endCounts = Integer.parseInt(repeatModeMap.get("endCounts").toString());
                            String whichWeeks = repeatModeMap.get("whichWeeks").toString();
                            int sameDayOrSameWeekOfTheMonth = Integer.parseInt(repeatModeMap.get("sameDayOrSameWeekOfTheMonth").toString());

                            repeatMode = new RepeatMode(
                                    repeatType,
                                    howOften,
                                    endCondition,
                                    endDateTime,
                                    endCounts,
                                    whichWeeks,
                                    sameDayOrSameWeekOfTheMonth
                            );

                            Event event = new Event(
                                    id,
                                    content,
                                    receivers,
                                    tag,
                                    dateTime,
                                    repeatMode,
                                    color,
                                    isActive,
                                    eventType,
                                    requestCode,
                                    isDelete
                            );

                            if(!isDelete) {
                                mDataset.add(event);
                            }
                        } // #END# for (String eventId : set)
                    }
                } // #END# if (dataSnapshot != null)

                if (mDataset.size() == 0) {
                    empty.setVisibility(View.VISIBLE);
                }

                Log.d(TAG, "mDataset size:" + mDataset.size());

                mAdapter = new EventAdapter(mDataset) {
                    @Override
                    public void onBindViewHolder(ViewHolder holder, int position) {
                        super.onBindViewHolder(holder, position);

                        final Event event = mDataset.get(position);

                        if (event.getIsActive()) {
                            holder.mIsActiveSC.setChecked(true);
                            holder.mEventHolderCV.setCardBackgroundColor(colors[event.getColor()]);
                        } else {
                            holder.mIsActiveSC.setChecked(false);
                            holder.mEventHolderCV.setCardBackgroundColor(ContextCompat.getColor(HelloActivity.this, R.color.disabled));
                        }

                        final DatabaseReference eventRef = mDatabase.child("events")
                                .child(mUser.getUid())
                                .child(event.getId());

                        holder.itemView.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                // TODO: 2016/11/26 handel event click operation
                                Log.d(TAG, event.getId());
                            }
                        });

                        holder.mEventHolderCV.setOnLongClickListener(new View.OnLongClickListener() {
                            @Override
                            public boolean onLongClick(View view) {
                                new AlertDialog.Builder(HelloActivity.this)
                                        .setTitle(getString(R.string.delete_event_confirm))
                                        .setPositiveButton(getString(R.string.delete), new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                // 删除这个事件，并且取消这个事件在设备上的 alarm
                                                Log.d(TAG, event.getId());
                                                deleteEvent(eventRef, event.getId(), (int) event.getRequestCode());
                                            }
                                        })
                                        .setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                            }
                                        }).show();
                                return true;
                            }
                        });

                        holder.mIsActiveSC.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                            @Override
                            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                                changeActive(eventRef, b);
                            }
                        });

                        //set alarm

                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
                        String dateTimeStr = event.getDateTime();

                        Calendar calendar = Calendar.getInstance();

                        try {
                            calendar.setTime(sdf.parse(dateTimeStr));
                            //compute next executing time
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }

                        if (event.getIsActive()) {
                            Log.d(TAG, "data changed: set an alarm");
                            setAlarm(event.getId(), (int) event.getRequestCode(), calendar.getTimeInMillis());
                        } else {
                            Log.d(TAG, "data changed: cancel an alarm");
                            cancelAlarm(event.getId(), (int) event.getRequestCode());
                        }
                    }
                };
                mRecycler.setAdapter(mAdapter);
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        };

        if (mUser != null) {
            DatabaseReference eventsRef = mDatabase.child("events").child(mUser.getUid());
            eventsRef.addValueEventListener(valueEventListener);
        }
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == ADD_EVENT_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                String datetime = dateTimeToLocal(data.getStringExtra("datetime"));
                Snackbar.make(
                        mRecycler,
                        String.format(getString(R.string.event_added_tip), datetime),
                        Snackbar.LENGTH_LONG
                ).show();
            }
            if (resultCode == RESULT_CANCELED) {
                Snackbar.make(mRecycler, getString(R.string.unsaved), Snackbar.LENGTH_LONG).show();
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_hello, menu);
        return true;
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_info) {
            // TODO: 2016/12/3 the message should include more detail information
            new AlertDialog.Builder(this)
                    .setTitle(getString(R.string.help))
                    .setMessage(descs[mEventType])
                    .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    }).show();
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.fab) {
            Intent intent = new Intent(HelloActivity.this, AddEventActivity.class);
            intent.putExtra("eventType", mEventType);
            startActivityForResult(intent, ADD_EVENT_REQUEST_CODE);
        }
    }

    private void changeActive(DatabaseReference eventRef, final boolean isActive) {

        eventRef.runTransaction(new Transaction.Handler() {
            @Override
            public Transaction.Result doTransaction(MutableData mutableData) {
                Event event = mutableData.getValue(Event.class);
                if (event == null) {
                    return Transaction.success(mutableData);
                }

                event.setIsActive(isActive);

                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
                String dateTimeStr = event.getDateTime();

                Calendar calendar = Calendar.getInstance();

                try {
                    calendar.setTime(sdf.parse(dateTimeStr));
                    //compute next executing time
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                if (calendar.getTime().compareTo(new Date()) < 0) {
                    calendar = getNextExecuteTime(calendar, event.getRepeatMode());
                    Log.d(TAG, "getNextExecuteTime:" + calendar.toString());
                }

                // calendar updated, then update event.DateTime
                String dateStr = sdf.format(calendar.getTime());
                event.setDateTime(dateStr);

                mutableData.setValue(event);

                String eventDateTimeLocal = dateTimeToLocal(event.getDateTime());

                String snackbarText = event.getIsActive() ? String.format(
                        getString(R.string.event_resume_tip),
                        eventDateTimeLocal
                ) : String.format(
                        getString(R.string.event_suspend_tip),
                        eventDateTimeLocal
                );

                Snackbar.make(mRecycler, snackbarText, Snackbar.LENGTH_LONG).show();

                return Transaction.success(mutableData);
            }

            @Override
            public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
                Log.d(TAG, "postTransaction:onComplete:" + databaseError);
            }
        });
    }

    private void deleteEvent(DatabaseReference eventRef, String eventId, int requestCode) {
        AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);

        Intent intent = new Intent(getApplicationContext(), NotificationReceiver.class);
        intent.putExtra("event_id", eventId);

        PendingIntent alarmIntent = PendingIntent.getBroadcast(
                getApplicationContext(),
                requestCode,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT
        );

        alarmMgr.cancel(alarmIntent);

        eventRef.child("isDelete").setValue(true).addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                Snackbar.make(mRecycler, getString(R.string.delete_successfully), Snackbar.LENGTH_LONG).show();
            }
        });
    }

    private String dateTimeToLocal(String dateTimeStr) {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());

        Date datetime = null;
        try {
            datetime = dateFormat.parse(dateTimeStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(datetime);

        String year = new SimpleDateFormat("yyyy", Locale.getDefault()).format(calendar.getTime());
        String month = new SimpleDateFormat("MM", Locale.getDefault()).format(calendar.getTime());
        String day = new SimpleDateFormat("dd", Locale.getDefault()).format(calendar.getTime());
        String week = new SimpleDateFormat("E", Locale.getDefault()).format(calendar.getTime());
        String hour = new SimpleDateFormat("HH", Locale.getDefault()).format(calendar.getTime());
        String minute = new SimpleDateFormat("mm", Locale.getDefault()).format(calendar.getTime());

        String dateStr = String.format(getResources().getString(R.string.default_date_picker), week, month, day, year);
        String timeStr = String.format(getResources().getString(R.string.default_time_picker), hour, minute);

        return dateStr + " " + timeStr;
    }
}
